﻿using System.Collections;
using System.ComponentModel;
using System.Reflection;

namespace PmSoft.Core.Extensions;

/// <summary>
/// 对象类型的扩展方法
/// </summary>
public static class ObjectExtensions
{
	/// <summary>
	/// 将对象转换为指定类型
	/// </summary>
	/// <typeparam name="T">目标类型</typeparam>
	/// <param name="value">要转换的对象</param>
	/// <returns>转换后的对象</returns>
	public static T? ConvertTo<T>(this object value)
	{
		var type = typeof(T);
		return (T?)ConvertTo(value, type);
	}

	/// <summary>
	/// 将对象转换为指定类型
	/// </summary>
	/// <param name="value">要转换的对象</param>
	/// <param name="type">目标类型</param>
	/// <returns>转换后的对象</returns>
	public static object? ConvertTo(this object value, Type type)
	{
		var realType = Nullable.GetUnderlyingType(type) ?? type;
		if (value == null) return Activator.CreateInstance(realType);

		if (realType.IsEnum)
		{
			if (value is string) return Enum.Parse(realType, value.ToString()!, true);
			return Enum.ToObject(realType, value);
		}

		if (!realType.IsInterface && realType.IsGenericType)
		{
			Type innerType = realType.GetGenericArguments()[0];
			ConstructorInfo[] constructors = realType.GetConstructors();
			ConstructorInfo? matchingConstructor = null;
			foreach (ConstructorInfo constructor in constructors)
			{
				ParameterInfo[] parameters = constructor.GetParameters();
				if (parameters.Length == 1 && parameters[0].ParameterType == innerType)
				{
					matchingConstructor = constructor;
					break;
				}
			}

			if (matchingConstructor != null)
			{
				object? innerValue = value.ConvertTo(innerType);
				return matchingConstructor.Invoke(new object?[] { innerValue });
			}
		}

		if (value is string valueStr)
		{
			if (realType == typeof(Guid))
				return new Guid(valueStr);

			if (realType == typeof(Version))
				return new Version(valueStr);
		}

		if (value is IEnumerable enumerable)
		{
			if (realType is { IsGenericType: true })
			{
				if (realType.IsInterface)
				{
					var desiredCollectionItemType = realType.GenericTypeArguments[0];
					var desiredCollectionType = typeof(IEnumerable<>).MakeGenericType(desiredCollectionItemType);

					if (desiredCollectionType.IsAssignableFrom(type))
					{
						var collectionType = typeof(List<>).MakeGenericType(desiredCollectionItemType);
						var collection = (IList)Activator.CreateInstance(collectionType)!;
						foreach (var item in enumerable)
						{
							var convertedItem = ConvertTo(item, desiredCollectionItemType);
							collection.Add(convertedItem);
						}

						return collection;
					}
				}
				else
				{
					var desiredCollectionItemType = realType.GenericTypeArguments[0];
					var collectionType = typeof(List<>).MakeGenericType(desiredCollectionItemType);
					var collection = (IList)Activator.CreateInstance(collectionType)!;
					foreach (var item in enumerable)
					{
						var convertedItem = ConvertTo(item, desiredCollectionItemType);
						collection.Add(convertedItem);
					}

					return collection;
				}
			}
		}

		var converter = TypeDescriptor.GetConverter(realType);
		if (converter.CanConvertFrom(realType))
			return converter.ConvertFrom(value);

		if (typeof(IConvertible).IsAssignableFrom(realType))
		{
			try
			{
				return Convert.ChangeType(value, realType);
			}
			catch
			{
				return realType.GetDefaultValue();
			}
		}

		return value;
	}

	/// <summary>
	/// 深拷贝对象
	/// </summary>
	/// <typeparam name="T">对象的类型</typeparam>
	/// <param name="original">要拷贝的对象</param>
	/// <returns>拷贝后的对象</returns>
	public static T? DeepCopy<T>(this T original)
	{
		var str = Json.Stringify(original);
		return Json.Parse<T>(str);
	}

	/// <summary>
	/// 判断属性是否为枚举类型
	/// </summary>
	/// <param name="propertyInfo">属性信息</param>
	/// <returns>如果是枚举类型，则为 true；否则为 false</returns>
	public static bool IsEnumType(this PropertyInfo propertyInfo)
	{
		if (propertyInfo == null)
			throw new ArgumentNullException(nameof(propertyInfo));

		Type propertyType = propertyInfo.PropertyType;

		// 检查是否为可空类型，并获取其基础类型
		Type underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;

		// 检查类型是否为枚举类型
		return underlyingType.IsEnum;
	}

	/// <summary>
	/// 判断类型是否为基本类型
	/// </summary>
	/// <param name="type">类型</param>
	/// <returns>如果是基本类型，则为 true；否则为 false</returns>
	public static bool IsBasicType(Type type)
	{
		if (type.IsValueType) // 值类型
		{
			return true;
		}
		if (type.IsPrimitive) // 检查是否为原始类型
		{
			return true;
		}
		if (type == typeof(decimal) || type == typeof(string) || type == typeof(char))
		{
			return true;
		}
		if (type.IsEnum) // 检查是否为枚举类型
		{
			return true;
		}
		return false;
	}
}


